<template>
  <view 
    class="fu-image"
    :class="{
      'fu-image--round': round,
      'fu-image--loading': loading,
      'fu-image--error': error,
      [`fu-image--${mode}`]: mode
    }"
    :style="wrapStyle"
    @click="onClick"
  >
    <!-- 实际图片 -->
    <image
      v-if="!error"
      ref="image"
      :src="showSrc"
      :mode="mode"
      :lazy-load="lazyLoad"
      :webp="webp"
      :show-menu-by-longpress="showMenuByLongpress"
      class="fu-image__img"
      :class="{ 'fu-image__img--blur': loading }"
      @load="onLoad"
      @error="onError"
    />
    
    <!-- 加载中占位 -->
    <view v-if="loading && showLoading" class="fu-image__loading">
      <slot name="loading">
        <fu-icon name="photo" size="48" color="#dcdee0" />
      </slot>
    </view>
    
    <!-- 加载失败占位 -->
    <view v-if="error && showError" class="fu-image__error">
      <slot name="error">
        <fu-icon name="photo-fail" size="48" color="#dcdee0" />
      </slot>
    </view>
  </view>
</template>

<script>
/**
 * fu-image 图片组件
 * @description 支持懒加载、渐进式加载和占位图的增强型图片组件
 * @property {String} src - 图片链接
 * @property {String} mode - 图片裁剪、缩放模式
 * @property {String} width - 宽度，默认单位 rpx
 * @property {String} height - 高度，默认单位 rpx
 * @property {Boolean} round - 是否显示为圆形
 * @property {Boolean} lazyLoad - 是否开启懒加载
 * @property {Boolean} showLoading - 是否显示加载中提示
 * @property {Boolean} showError - 是否显示加载失败提示
 * @property {Boolean} showMenuByLongpress - 是否开启长按图片显示识别小程序码菜单
 * @property {Boolean} webp - 是否优先使用 webp 格式
 * @event {Function} click - 点击图片时触发
 * @event {Function} load - 图片加载完成时触发
 * @event {Function} error - 图片加载失败时触发
 */
export default {
  name: 'fu-image',
  props: {
    src: {
      type: String,
      default: ''
    },
    mode: {
      type: String,
      default: 'aspectFill'
    },
    width: {
      type: [String, Number],
      default: '100%'
    },
    height: {
      type: [String, Number],
      default: '320'
    },
    round: {
      type: Boolean,
      default: false
    },
    lazyLoad: {
      type: Boolean,
      default: true
    },
    showLoading: {
      type: Boolean,
      default: true
    },
    showError: {
      type: Boolean,
      default: true
    },
    showMenuByLongpress: {
      type: Boolean,
      default: false
    },
    webp: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      loading: true,
      error: false,
      showSrc: ''
    }
  },
  computed: {
    wrapStyle() {
      const style = {}
      
      if (this.width) {
        style.width = this.addUnit(this.width)
      }
      
      if (this.height) {
        style.height = this.addUnit(this.height)
      }
      
      return style
    }
  },
  watch: {
    src: {
      handler(val) {
        this.loadImage(val)
      },
      immediate: true
    }
  },
  methods: {
    // 添加单位
    addUnit(value) {
      if (!value) return ''
      value = String(value)
      return /^\d+(\.\d+)?$/.test(value) ? `${value}rpx` : value
    },
    
    // 加载图片
    loadImage(src) {
      if (!src) {
        this.showSrc = ''
        this.loading = false
        this.error = true
        return
      }
      
      this.loading = true
      this.error = false
      this.showSrc = src
    },
    
    // 图片加载完成
    onLoad(event) {
      this.loading = false
      this.error = false
      this.$emit('load', event)
    },
    
    // 图片加载失败
    onError(event) {
      this.loading = false
      this.error = true
      this.$emit('error', event)
    },
    
    // 点击图片
    onClick(event) {
      this.$emit('click', event)
    }
  }
}
</script>

<style lang="scss" scoped>
.fu-image {
  position: relative;
  display: inline-block;
  overflow: hidden;
  
  &__img {
    display: block;
    width: 100%;
    height: 100%;
    
    &--blur {
      filter: blur(10rpx);
      transform: scale(1.1);
      transition: all 0.3s;
    }
  }
  
  &__loading,
  &__error {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--fu-background-color-light);
    color: var(--fu-text-color-disabled);
  }
  
  &--round {
    border-radius: 50%;
    
    .fu-image__img {
      border-radius: 50%;
    }
  }
  
  &--widthFix {
    height: auto;
  }
  
  &--heightFix {
    width: auto;
  }
  
  &--loading {
    .fu-image__img {
      opacity: 0;
    }
  }
  
  &--error {
    .fu-image__img {
      display: none;
    }
  }
}
</style> 